package com.pro.framework.generator.main.generator.main;

import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.StrUtil;
import com.pro.framework.api.util.AssertUtil;
import com.pro.framework.api.util.StrUtils;
import com.pro.framework.generator.main.generator.AbsGenerator;
import com.pro.framework.api.model.GeneratorDevConfig;
import com.pro.framework.generator.utils.StringFormater;
import com.pro.framework.javatodb.model.JTDTableInfo;
import com.pro.framework.javatodb.service.JTDServiceImpl;
import com.pro.framework.javatodb.util.JTDAssertUtil;
import com.pro.framework.javatodb.util.JTDUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * velocity 代码生成
 */
@Slf4j
public class GeneratorUtil_EnumAuthRoute extends AbsGenerator {

    public static final String DEMO_LABEL = ", \"项目产品\",";
    public static final String DEMO_CODE = "demo";
    private static final String DEMO_REGEX = "^\\s*(//\\s*|)demo";

    @SneakyThrows
    public static void generate(List<Class<?>> classes, boolean existModifyFlag) {
        init();

        // 读取 YAL
        GeneratorDevConfig generatorConfig = mapper.readValue(new ClassPathResource("system-dev.yml").getFile(),
                GeneratorDevConfig.class);
        String platformShortName = generatorConfig.getPlatformShortName();
        generatorConfig.setPlatformShortNameUpperFirst(StrUtil.upperFirst(platformShortName));


        List<JTDTableInfo> tableInfos = classes.stream().filter(aClass -> {
            if (!aClass.getPackageName().contains(platformShortName)) {
                log.warn("{} 跳过公共模块实体 ", aClass.getSimpleName());
                return false;
            }
            return true;
        }).map(aClass -> {
            JTDTableInfo jtdTableInfo = JTDServiceImpl.buildTableFullInfoFromClass(aClass, jtdProperties,
                    JTDUtil::fieldFilter);
            JTDAssertUtil.notNull(jtdTableInfo, aClass + "不存在JTDTable注解配置");
            return jtdTableInfo;
        }).filter(m -> {
            if (m.getModule().isEmpty()) {
                log.warn("{} 模块未定义, 忽略", m.getEntityName());
                return false;
            }
            return true;
        }).toList();

        Map<String, List<JTDTableInfo>> modules = tableInfos.stream()
                .collect(Collectors.groupingBy(JTDTableInfo::getModule));
        modules.forEach((module, subTableInfos) -> dealModule(module, subTableInfos, generatorConfig, existModifyFlag));
    }

    @SneakyThrows
    private static void dealModule(String module, List<JTDTableInfo> subTableInfos, GeneratorDevConfig generatorConfig, boolean existModifyFlag) {
        generatorConfig.setModuleUpperFirst(StrUtils.firstToUpperCase(module));
        generatorConfig.setModule(module);
        // 读取枚举内容
        String enumPath = StringFormater.format(
                "{workspace}/{platformName}/platform/{platformShortName}-services/{platformShortName}-site-content-service/src/main/java/com/pro/{platformShortName}/sitecontent/enums/init/EnumAuthRoute{platformShortNameUpperFirst}{moduleUpperFirst}.java",
                generatorConfig);

        // 按行读取 enumAuthRouteFile 文件全内容到 fileLines
        List<String> fileLines = Files.readAllLines(Paths.get(enumPath));
        // 另外读出以demo开头的每一行 (trim()以后)
        Pattern compile = Pattern.compile(DEMO_REGEX);
        List<String> fileLinesDemo = fileLines.stream()
                .filter(line -> compile.matcher(line).find())
                .map(s -> s.trim().startsWith("//") ? s.replaceFirst("//", "") : s)
                .toList();
        AssertUtil.notEmpty(fileLinesDemo, "_没有包含demoLines", enumPath);

        Matcher matcher = Pattern.compile("\\d+").matcher(fileLinesDemo.get(0));
        String routeId = matcher.find() ? matcher.group() : "100200";
        String routeIdHead = routeId.substring(0, routeId.length() - 2);


        for (JTDTableInfo jtdTableInfo : subTableInfos) {
            dealTable(fileLines, fileLinesDemo, routeIdHead, jtdTableInfo, existModifyFlag);
        }
        Files.write(Paths.get(enumPath), fileLines);  // 默认覆盖原文件
    }

    private static void dealTable(List<String> fileLines, List<String> fileLinesDemo, String routeIdHead, JTDTableInfo jtdTableInfo, boolean existModifyFlag) {
        String entityName = jtdTableInfo.getEntityName();
        Integer entityId = jtdTableInfo.getEntityId();
        String label = jtdTableInfo.getLabel();
        // 2.删除enumAuthRouteFile中已存在的行
        Set<String> oldLines = fileLines.stream()
                .filter(line -> line.trim().startsWith(entityName + "_") || line.trim().startsWith("//    "+ entityName + "_") || line.trim().startsWith(entityName + "("))
                .collect(Collectors.toSet());
        if (!oldLines.isEmpty() && !existModifyFlag) {
            return;
        }
        oldLines.forEach(fileLines::remove);

        // 3.根据demo开的几行(内容),复制新的行 (添加到第一个;所在行的前一行)
        List<String> fileLinesNew = fileLinesDemo.stream()
                .map(s -> s.replaceAll(DEMO_CODE, entityName)
                        .replaceAll(DEMO_LABEL, ", \"" + label + "\",")
                        .replaceAll(", " + routeIdHead, ", " + entityId))
                .toList();


        int firstIndex = IntStream.range(0, fileLines.size())
                .filter(i -> fileLines.get(i).trim().contains("demo_ALL("))
                .findFirst()
                .orElse(-1) + 1;
        String enumLastLine = fileLines.stream()
                .filter(line -> !line.startsWith("package") && !line.startsWith("import") && line.contains(";"))
                .findFirst()
                .orElse("");
        int lastIndex = fileLines.indexOf(enumLastLine);
        for (String line : fileLinesNew) {
            fileLines.add(lastIndex, line);
            lastIndex++;
            log.warn("写入菜单枚举 {}", line);
        }
        List<String> subList = new ArrayList<>(fileLines.subList(firstIndex, lastIndex));

        subList.sort((s1, s2) -> {
            boolean s1IsComment = s1.startsWith("//");
            boolean s2IsComment = s2.startsWith("//");


            if (s1IsComment && !s2IsComment) return -1; // s1 在前
            if (!s1IsComment && s2IsComment) return 1;  // s2 在前

            int len = Math.min(s1.length(), s2.length());
            for (int i = 0; i < len; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    boolean c1IsLetterOrDigit = Character.isLetterOrDigit(c1);
                    boolean c2IsLetterOrDigit = Character.isLetterOrDigit(c2);
                    if (c1IsLetterOrDigit && !c2IsLetterOrDigit) return 1;
                    if (!c1IsLetterOrDigit && c2IsLetterOrDigit) return -1;
                    return c1 - c2; // 都是字母/数字或者都不是，按ASCII顺序
                }
            }
            return s1.compareTo(s2);                     // 都是注释或都不是注释，按内容排序
        });

        // 覆盖回原列表
        for (int i = 0; i < subList.size(); i++) {
            fileLines.set(firstIndex + i, subList.get(i));
        }
    }

//    public static void main(String[] args) {
//        System.out.println("demo(ADMIN, catalog_snowball, MENU, \"项目产品\", \"/snowball/demo\", null, null, null, null, null, null, 100200, null),".replaceAll());
//    }
}
